signal関数は、シグナル(非同期イベント)が発生したときに、そのシグナルを受信して、シグナル特有の処理を行うシグナル処理関数(シグナルハンドラ)を登録します。
#include <signal.h>
void (*signal(int signum, void (*sighandler)(int signum)))(int signum);
signumはシグナル処理関数に対応付けする、シグナルを指定します。
*sighandlerはSIG_IGN、SIG_DFL、シグナル処理関数のアドレスのいずれかを指定します。
戻り値として、signumに対応するシグナル処理関数の値を返します。また、エラーの場合はSIG_ERRを返します。
第1引数のsignumに指定できる値は、signal.hファイルに定義されています。また、UNIX系OSの場合は、kill -l
コマンドで表示できます。下表は一般的なシグナルのみで、システムにより異なります。
定数名 | 値 | 意味 |
---|---|---|
SIGINT | 2 | キーボードからの割り込み(Interrupt) |
SIGQUIT | 3 | キーボードによる中止(Quit) |
SIGILL | 4 | 不正な命令 |
SIGABRT | 6 | abort関数からの中断(Abort) |
SIGFPE | 8 | 浮動小数点例外 |
SIGUSR1 | 10 | ユーザ定義シグナル1 |
SIGSEGV | 11 | 不正なメモリ参照 |
SIGUSR2 | 12 | ユーザ定義シグナル2 |
SIGPIPE | 13 | パイプ破壊(読み手の無いパイプへの出力) |
SIGALRM | 14 | alarmシステムコールからのタイマーシグナル |
SIGTERM | 15 | 終了(termination) |
SIGCHLD | 17 | 子プロセスの一旦停止(stop)または終了 |
SIGCONT | 18 | 一旦停止(stop)からの再開 |
SIGTSTP | 20 | 端末(tty)から入力された一旦停止(stop) |
SIGTTIN | 21 | バックグランドプロセスのtty入力 |
SIGTTOU | 22 | バックグランドプロセスのtty出力 |
第2引数の*sighandlerにSIG_IGNを指定した場合は、signumに指定したシグナルを無視し、SIG_DFLを指定した場合は、デフォルトの動作を行います。また、シグナル処理関数のアドレスを指定した場合は、signumを引数としてシグナル処理関数を呼び出します。
シグナル処理関数を実行すると、登録はリセットされますので、同じ処理を行いたい場合はsignal関数を再度実行する必要があります。また、SIGKILLとSIGSTOPシグナルは捕捉できませんし、無視することもできません。
次の例題プログラムはSIGINTシグナル(CtrlキーとCキーを同時に押下することにより発生)を3回発行すると終了します。
プログラム 例
#include <stdio.h> #include <stdlib.h> #include <signal.h> /* ユーザ定義関数の宣言 */ void SetSignal(int SignalName); void SigHandler(int SignalName); void Input(void); int main(void) { SetSignal(SIGINT); Input(); return 0; } void Input(void) { while(1) { printf('実行中!!\n'); sleep(3); } return; } /* シグナルの設定 */ void SetSignal(int p_signame) { if (signal(p_signame, SigHandler) == SIG_ERR) { /* シグナル設定エラー */ printf('シグナルの設定が出来ませんでした。終了します\n'); exit(1); } return; } /* シグナル受信/処理 */ void SigHandler(int p_signame) { static int sig_cnt = 0; ++sig_cnt; if (sig_cnt <= 2) { printf('%d回目の割り込みです。無視します\n', sig_cnt); } else { printf('%d回目の割り込みです。終了します\n', sig_cnt); exit(0); } /* シグナルの再設定 */ SetSignal(p_signame); return; }
例の実行結果
$ ./signal.exe 実行中!! 実行中!! 実行中!! 1回目の割り込みです。無視します 実行中!! 実行中!! 2回目の割り込みです。無視します 実行中!! 実行中!! 実行中!! 実行中!! 3回目の割り込みです。終了します $